需求表达的艺术#
在使用 Claude Code 的过程中,我经常遇到这样的情况:同样的需求,有时候 AI 给出的方案非常精准,有时候却只能给一些模糊的建议。比如,我想重构一段代码,直接说"重构这段代码",AI 可能只做一些表面的优化;但如果我说"作为架构师,审查这段代码的设计问题,并给出重构方案",AI 会从更高的层次思考,给出系统性的改进建议。
与 AI 对话不只是"说清楚需求"这么简单,如何表达需求、如何引导 AI 的思考方向,都会显著影响输出质量。这就是 Prompt Engineering(提示工程)要解决的问题。
在上一篇攻略中,我们学习了上下文工程,强调"输入决定输出质量"。如果说上下文工程关注的是"提供什么信息",那么 Prompt Engineering 关注的就是"如何表达需求"。两者的关系可以这样理解:
上下文工程:提供完整的视野(代码、文档、项目配置)
↓
Prompt Engineering:表达清晰的意图(我想要什么、怎么做)
↓
高质量输出这篇文章,我会系统地介绍 Prompt Engineering 的 6 个核心技巧,帮助你在使用 Claude Code 时更高效地表达需求。
核心技巧 1:提供充分上下文#
什么是"充分"?#
不是越多越好,而是让 LLM 能够构建完整推理链所需的最小信息集。
对比案例#
场景:Next.js 页面加载慢
Prompt A(信息不足):
我的 Next.js 页面加载很慢,帮我分析原因。LLM 的推理链(卡住):
提取问题:页面加载慢
↓
检索知识:什么会导致页面慢?
↓
【卡住】没有具体信息,只能列举所有可能性
↓
输出通用答案:可能是请求慢、渲染慢、资源加载慢...Prompt B(充分上下文):
我的 Next.js 页面 `/dashboard` 加载很慢(首屏 5 秒)。
观察到的现象:
- Network 面板显示一个 API 请求耗时 3.5 秒
- 该请求是 `/api/users`,返回 10MB 数据
- 页面渲染时使用了 `map()` 遍历所有数据
请分析可能的性能瓶颈,并建议优化方案。LLM 的推理链(完整):
提取问题:页面加载慢(5秒)
↓
检索上下文:API 请求 3.5 秒 + 返回 10MB + 前端 map() 遍历
↓
推理:3.5秒占了总时长的 70% → 主要瓶颈在请求
↓
深入推理:10MB 数据量过大 + 前端全量渲染 → 双重问题
↓
输出针对性方案:
1. 后端分页/过滤,减少数据量
2. 前端虚拟滚动,只渲染可见部分
3. 考虑增量加载Prompt B 提供了哪些关键信息?#
- 具体位置:
/dashboard页面(不是泛泛的"页面") - 可量化指标:5 秒、3.5 秒、10MB(让问题可度量)
- 关键证据:API 请求、数据量、前端处理方式(推理的线索)
- 明确期望:分析瓶颈 + 优化方案(输出方向)
使用场景#
- 适用:几乎所有场景,这是最基础的技巧
- 特别重要:问题诊断、性能优化、Bug 修复
核心技巧 2:明确角色与目标#
角色设定的本质价值#
角色设定不是形式主义,而是触发 LLM 的专业知识检索和系统性思考。
对比案例#
场景:代码重构
Prompt A(无角色):
请帮我重构这段代码:
@components/UserList.tsx
要求:
- 提取重复逻辑
- 优化性能
- 遵循 React 最佳实践AI 可能的输出:
- 表面优化:提取几个函数、用 useCallback 包裹
- 缺乏深度:只关注代码层面,不考虑架构
Prompt B(指定角色):
作为一位资深的 React 架构师,请审查并重构这段代码:
@components/UserList.tsx
审查重点:
- 识别代码异味和性能瓶颈
- 评估组件职责是否单一
- 建议架构层面的改进
要求:
- 先指出问题,再给出重构方案
- 解释每个改动的原因
- 遵循 React 最佳实践AI 可能的输出:
- 系统性分析:从架构、职责划分、性能等多个维度审查
- 专业深度:提出状态提升、组件拆分、自定义 Hook 等架构级建议
- 说明原因:解释为什么这样改进
何时需要角色设定?#
需要:
- 需求不明确,需要专业视角补充
- 需要系统性思考,而非点状执行
- 需要特定领域的专业知识
不需要:
- 需求非常明确,无需补充
- 简单的执行类任务
- 你已经提供了详细的规范
实用原则#
判断是否需要角色设定,问自己:
- 我的需求是否足够明确?(不明确 → 需要角色)
- 我需要 AI "照单执行"还是"发挥专业判断"?(后者 → 需要角色)
- 这个任务是否需要专业知识?(需要 → 指定专业角色)
核心技巧 3:使用示例引导(Few-shot Learning)#
你是否遇到过这样的情况:让 AI 写 Git commit message,结果每次格式都不一样,有时是"修复bug",有时是"Fix: 修复了登录问题",有时又是"修复登录功能的bug"。你明明说了要求,但 AI 总是理解偏差。
这是因为规则描述是抽象的,AI 需要"推断"你的标准。而给出具体示例,AI 可以直接"复制"模式。
规则 vs 示例:LLM 的视角#
规则描述(抽象):
"使用动词开头,说明改动的原因"
LLM 思考:
add? adding? added? 还是 adds?
原因是指什么原因?
→ LLM 需要"推断"你的标准具体示例(模式):
✅ 好的示例:
- "Add: 新增用户偏好保存到 localStorage"
- "Fix: 修复移动端导航栏遮挡内容的问题"
LLM 识别:
动词原形 + 冒号 + 空格 + 中文描述
→ LLM 直接"复制"这个模式关键差异:
- 规则 = 让 AI 理解抽象概念,然后生成
- 示例 = 让 AI 识别具体模式,然后模仿
LLM 更擅长模式匹配,而非抽象推理。
正例 + 反例 = 明确边界#
只有正例:
✅ "Fix: 修复移动端导航栏遮挡内容的问题"
AI 学到:这样写是对的
但 AI 不知道:哪些写法是错的正例 + 反例:
✅ "Fix: 修复移动端导航栏遮挡内容的问题"
❌ "Fix bug"(太模糊,没说清楚修了什么)
❌ "修改了 3 个文件"(关注点错误,应该说影响)
AI 学到:
- 这样写是对的
- 这样写是错的
→ 明确了"详细程度"的边界实战案例#
场景:为函数添加 JSDoc 注释
Prompt(Few-shot):
请为以下函数添加 JSDoc 注释。
## 风格要求
- 简洁实用,避免冗余描述
- 说明函数作用、参数含义、返回值
- 如果函数逻辑显而易见,注释可以更精简
## 参考示例
✅ 推荐风格:
/**
* 计算两个数的和
* @param {number} a - 第一个数
* @param {number} b - 第二个数
* @returns {number} 两数之和
*/
function add(a, b) {
return a + b;
}
/**
* 从数组中过滤出偶数
* @param {number[]} arr - 原数组
* @returns {number[]} 只包含偶数的新数组
*/
function filterEven(arr) {
return arr.filter(n => n % 2 === 0);
}
❌ 避免:
/**
* 这个函数用于处理内部的复杂逻辑并返回结果
* @param {any} data - 数据
* @returns {any} 结果
*/
function process(data) { ... }
// 问题:描述模糊,类型不明确
/**
* 此函数接收一个数组作为参数,然后遍历数组中的每一个元素,
* 对每个元素进行判断,如果是偶数则保留,最后返回一个新数组
* @param {number[]} arr - 输入的数组参数
* @returns {number[]} 返回过滤后的数组
*/
function filterEven(arr) { ... }
// 问题:过于冗余,实现细节不需要在注释中说明
## 目标函数
@utils/calculator.ts 中的所有函数示例数量选择#
1-shot(1 个示例):
- 适合:简单模式、风格明确
Few-shot(2-3 个示例):
- 适合:中等复杂度、需要展示变化
Many-shot(5+ 个示例):
- 适合:复杂模式、需要覆盖多种情况
- 注意:消耗更多 Token
原则:够用就好,不是越多越好。
使用场景#
- 风格对齐(代码注释、commit message、文档格式)
- 格式规范(API 文档、测试用例)
- 复杂模式识别(代码重构模式、命名规范)
核心技巧 4:要求推理过程(Chain-of-Thought)#
为什么推理过程能降低 AI 幻觉?#
直接给答案(无推理):
AI 思考过程(内部,你看不到):
检索知识 → [跳跃] → 给出结论
问题:中间的推理步骤被跳过,容易出现逻辑漏洞展示推理过程:
AI 思考过程(外部,你能看到):
第 1 步:识别问题类型
第 2 步:列举可能原因
第 3 步:逐一分析概率
第 4 步:得出结论
效果:每一步都需要有依据,减少了"臆测"的空间类比:学生做数学题
- 直接写答案 → 容易算错
- 写出推导步骤 → 每步都要自洽,错误率降低
Chain-of-Thought 的三个核心价值#
1. 可解释性
- 你知道 AI 是怎么得出结论的
- 你可以判断这个推理是否靠谱
- 你可以在推理的某一步介入修正
2. 可靠性
- 强制 AI 展示中间步骤,减少"跳跃式推理"
- 每一步都需要有依据,降低"编造"的概率
- AI 在写推理过程时,会进行自我校验
3. 可迁移性
- 你看到了 AI 的分析框架
- 下次遇到类似问题,你可以套用这个框架
- 从"依赖 AI"到"学会方法论"
实战案例#
场景:React 组件频繁重渲染
Prompt(要求推理):
作为前端性能优化专家,请帮我分析并解决 React 组件的重渲染问题。
## 背景
项目:Next.js + React 18
问题组件:@components/UserList.tsx
观察到的现象:
- 滚动列表时页面卡顿
- 每次滚动触发 5-10 次 UserList 重渲染
- Console 日志显示频繁的 "UserList rendered"
## 分析要求
请按以下步骤分析,并展示每一步的推理过程:
**第 1 步:诊断重渲染原因**
- 检查 props 是否每次都是新引用(对象/数组/函数)
- 检查父组件是否频繁 setState
- 检查 context 是否不必要地更新
- 列出可能的原因,并说明判断依据
**第 2 步:定位触发点**
- 找出具体是哪个 props/state/context 导致重渲染
- 解释为什么这个变化会触发重渲染
- 评估这个重渲染是否必要
**第 3 步:设计优化方案**
- 列出 2-3 种可行的优化方案
- 对比各方案的优劣(效果/成本/风险)
- 推荐最佳方案并说明理由
**第 4 步:实施优化**
- 给出具体的代码修改
- 解释每个修改的原理
- 说明如何验证优化效果
## 工作流程
1. 先展示完整的分析思路(步骤 1-3)
2. 等我确认后,再实施优化(步骤 4)使用场景#
适用:
- 复杂问题诊断
- 技术选型
- 架构设计
- 代码优化
不适用:
- 简单执行类任务
- 明确答案的知识查询
实用技巧#
技巧 1:明确要求推理步骤
不要:请分析一下这个问题
而是:请按以下步骤分析:1) ... 2) ... 3) ...技巧 2:要求"解释推理过程" 常用话术:
- "请解释你的思考过程"
- "请说明每个建议的依据"
- "请先分析,再给出结论"
- "请展示你的推理链"
核心技巧 5:分步骤引导#
假设你要做一个大规模的代码库重构,直接让 AI 一次性完成,结果改了几十个文件,运行测试发现到处都是错误,你不知道是哪一步出的问题。如果分步执行:先写测试 → 重构核心模块 → 验证 → 重构周边代码 → 最终验证,每一步都可控,出错了也容易定位。
这就是分步骤引导的价值:将复杂任务拆解为可控的小步骤。
与 Chain-of-Thought 的区别#
Chain-of-Thought:要求 AI 展示思考过程 分步骤引导:将任务本身拆解为多个执行步骤
类比:
- Chain-of-Thought = 让学生展示解题思路
- 分步骤引导 = 把大作业拆成小任务
步骤性质不同#
Chain-of-Thought 的步骤 = 思维步骤
步骤 1:识别问题 → 思考环节
步骤 2:分析原因 → 思考环节
步骤 3:设计方案 → 思考环节
步骤 4:实施优化 → 执行环节分步骤引导的步骤 = 执行步骤
步骤 1:重构状态管理 → 执行环节
步骤 2:优化渲染 → 执行环节
步骤 3:添加监控 → 执行环节两阶段策略:组合使用#
当你对需求没有完整概念时,可以先用 Chain-of-Thought 分析,再用分步骤引导执行。
实战案例:博客全文搜索功能
阶段 1:Chain-of-Thought(分析决策)
作为全栈架构师,请帮我设计博客的全文搜索功能。
请按以下思路分析:
1. **技术方案对比**
- 列出主流方案(Algolia、ElasticSearch、自建索引等)
- 分析各方案的优劣(成本、性能、维护难度)
2. **适配我的场景**
- 我的博客:Next.js + Markdown 文件
- 文章数量:约 100 篇,增长缓慢
- 预算有限,希望自托管
3. **推荐方案**
- 基于分析给出推荐
- 说明推荐理由
- 列出实施的关键步骤阶段 2:分步骤引导(执行实施)
很好!请按你推荐的方案,分步实施:
## 第 1 步:构建索引脚本
- 创建 `scripts/build-search-index.js`
- 扫描 @_blogs/ 目录
- 提取每篇文章的:title、description、content(前 200 字)
- 输出 `public/search-index.json`
## 第 2 步:集成到构建流程
- 在 `package.json` 的 build 脚本中添加索引生成
- 确保每次构建都更新索引
## 第 3 步:实现搜索组件
- 创建 `@components/Search.tsx`
- 使用 Fuse.js 加载索引
- 实现搜索逻辑和结果展示
## 第 4 步:添加到导航栏
- 在 `@components/Navbar.tsx` 中引入 Search 组件
- 添加快捷键支持(Cmd+K)
每完成一步,我会验证后再继续下一步。如何选择?#
使用 Chain-of-Thought 当:
- 你不确定怎么做
- 需要 AI 的专业判断
- 想学习 AI 的思考方式
使用分步骤引导当:
- 任务复杂,需要拆解
- 步骤有依赖关系
- 想控制执行节奏
组合使用当:
- 复杂且不确定的任务
- 先分析决策,再执行实施
核心技巧 6:设定输出格式#
你让 AI 分析代码问题,它回复了一大段话:"这段代码存在性能问题,建议使用 useCallback,另外 key 也缺失,还有状态管理可以优化..."。你读完还要自己梳理:哪些问题优先?哪些可以缓缓?
如果你要求 AI 用表格输出:
| 问题 | 优先级 | 影响 |
|---|---|---|
| 缺少 useCallback | P0 | 性能 |
| 缺少 key | P0 | 功能 |
| 状态管理混乱 | P1 | 可维护性 |
一眼就能看出优先级,直接决策。这就是设定输出格式的价值。
为什么格式化能强制 AI 更全面?#
自由格式(无结构):
"请分析这段代码的问题"
AI 思考过程:
想到什么说什么 → 可能遗漏某些维度结构化格式(有框架):
"请分析:
| 问题 | 严重性 | 影响 |"
AI 思考过程:
每个问题都要填三个字段 → 强制思考"这个问题的严重性和影响是什么"
表格格式 → 暗示需要列举多个问题,不能只说一个类比:
- 自由作文 vs 填空题
- 自由发言 vs 结构化汇报
效果:结构就是一种"检查清单",确保不遗漏关键信息。
三个核心价值#
1. 可读性 - 快速提取关键信息
对比:
无格式:"代码存在性能问题,建议使用 useCallback,另外 key 也缺失..."
→ 需要自己梳理:哪些是问题?哪些优先?
有格式:
| 问题 | 优先级 |
|------|--------|
| 缺少 useCallback | P0 |
| 缺少 key | P0 |
| 状态管理混乱 | P1 |
→ 一眼看出优先级,直接决策2. 可用性 - 便于后续处理
表格/JSON 格式的输出可以:
- 直接参考执行("根据表格中 P0 优先级的问题...")
- 导入工具处理(任务管理、自动化脚本)3. 完整性 - 强制系统性思考
结构化格式会暗示需要覆盖多个维度,减少遗漏。
常用输出格式模板#
1. 表格格式(对比分析)
| 维度 | 方案 A | 方案 B | 推荐 |
|------|--------|--------|------|适用:技术选型对比、方案优劣分析
2. 检查清单(完整性保证)
## 功能检查
- [ ] 核心功能
- [ ] 边界情况
- [ ] 错误处理
- [ ] 性能优化适用:代码审查、功能验收
3. 分级列表(优先级排序)
## P0(必须修复)
1. [问题]
## P1(建议修复)
1. [问题]适用:Bug 修复、性能优化
4. 结构化文档(标准格式)
## 概述
## 核心内容
## 示例
## 注意事项适用:API 文档、技术规范
5. JSON/YAML(可编程处理)
{
"tasks": [...],
"dependencies": [...],
"estimatedTime": "..."
}适用:集成到工作流、自动化处理
通用 Prompt 范式#
基于以上 6 个核心技巧,这里提供一个通用的 Prompt 范式。根据任务复杂度,你可以选择性使用各个模块。
[一句话概括任务目标]
## 背景(可选,复杂任务建议加上)
- 为什么需要这个功能?
- 要解决什么问题?
- 当前的痛点是什么?
## 文件与位置
- 新建:`@path/to/NewFile.tsx`
- 修改:`@path/to/ExistingFile.tsx` 中的 `xxx` 函数
- 引入:在 `@path/to/Consumer.tsx` 中使用
## 功能需求
1. 核心功能点 1
- 具体行为描述
- 关键算法/逻辑(如有)
2. 核心功能点 2
- ...
## 技术规范
- 使用的技术栈/库
- 代码风格:参考 `@STYLE_GUIDE.md`
- 命名约定:驼峰式/下划线等
- 性能要求(如有)
## 约束条件(可选)
- 必须兼容 xxx
- 不能修改 xxx 接口
- 必须使用 xxx 库
## 边界情况(关键场景,不求全但求准)
- 空数据/异常数据如何处理
- 用户异常操作如何响应
- 移动端/桌面端差异
- 性能边界(如大数据量)
## 测试用例/示例(可选但推荐)
- 输入 A → 预期输出 B
- 场景 X → 预期行为 Y
## 预期输出
- [ ] 直接给出完整代码
- [ ] 先给方案,待确认后实现
- [ ] 使用 Plan Mode,先规划再执行
- [ ] 给出 2-3 种方案对比各模块的核心作用#
| 模块 | 作用 | 何时必需 |
|---|---|---|
| 背景 | 帮助 AI 理解上下文,做更好决策 | 复杂任务、需要技术选型 |
| 文件位置 | 明确操作范围,避免歧义 | 几乎所有代码任务 |
| 功能需求 | 明确要实现什么 | 所有任务 |
| 技术规范 | 约束实现方式,保证一致性 | 团队协作、有规范要求 |
| 约束条件 | 避免 AI "自由发挥"触碰红线 | 有技术/业务限制 |
| 边界情况 | 提醒关键场景,提升代码健壮性 | 生产代码 |
| 测试用例 | 明确验收标准,便于验证 | 逻辑复杂的功能 |
| 预期输出 | 控制 AI 工作流程 | 不确定/复杂任务 |
快速检查清单#
写完 Prompt 后,问自己:
- AI 能否理解我要做什么?(目标明确)
- AI 知道在哪里做吗?(位置明确)
- AI 知道如何验证做对了吗?(标准明确)
- 关键约束我都说清楚了吗?(边界明确)
- 我期望 AI 先规划还是直接干?(流程明确)
6 个核心技巧总结#
| 技巧 | 核心作用 | 适用场景 |
|---|---|---|
| 1. 提供充分上下文 | 让 AI 能推理 | 几乎所有场景 |
| 2. 明确角色与目标 | 触发专业知识、补充需求 | 需求不明确时 |
| 3. 使用示例 | 模式学习、风格对齐 | 需要特定格式/风格 |
| 4. 要求推理过程 | 降低幻觉、可解释性 | 复杂决策、问题诊断 |
| 5. 分步骤引导 | 拆解任务、控制节奏 | 复杂任务、有依赖 |
| 6. 设定输出格式 | 提升可读性、完整性、可用性 | 需要结构化输出 |
核心原则与实践#
Prompt Engineering 不是玄学,而是基于 LLM 工作机制的科学方法。核心原则:
- 信息充分:提供 AI 构建推理链所需的关键信息
- 表达清晰:使用结构化、明确的语言表达需求
- 引导思考:通过示例、步骤、格式引导 AI 的思考方向
- 控制流程:明确期望的工作流程和输出格式
在实际使用中,你可以:
- 从通用 Prompt 范式开始,根据任务选择性使用各个模块
- 遇到复杂任务,采用两阶段策略:先 Chain-of-Thought 分析,再分步执行
- 用快速检查清单验证 Prompt 质量
Prompt Engineering 是一项需要持续实践的技能。在使用 Claude Code 时,有意识地应用这些技巧,观察输出质量的变化,逐步建立自己的 Prompt 模式库。
下一篇攻略,我们会深入学习 Claude Code 的整体架构与核心特性,理解它与其他 AI 工具的本质差异。